<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> 
    <title> - 天地维杰网</title>
    <meta name="keywords" content="系统架构,shutdown,不与天斗,Domino,博客,程序员,架构师,笔记,技术,分享,java,Redis">
    
    <meta property="og:title" content="">
    <meta property="og:site_name" content="天地维杰网">
    <meta property="og:image" content="/img/author.jpg"> 
    <meta name="title" content=" - 天地维杰网" />
    <meta name="description" content="天地维杰网 | 博客 | 软件 | 架构 | Java "> 
    <link rel="shortcut icon" href="http://www.shutdown.cn/img/favicon.ico" />
    <link rel="apple-touch-icon" href="http://www.shutdown.cn/img/apple-touch-icon.png" />
    <link rel="apple-touch-icon-precomposed" href="http://www.shutdown.cn/img/apple-touch-icon.png" />
    <link href="http://www.shutdown.cn/js/vendor/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/js/vendor/fancybox/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/css/main.css" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/css/syntax.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" id="hexo.configuration">
  var NexT = window.NexT || {};
  var CONFIG = {
    scheme: 'Pisces',
    sidebar: {"position":"left","display":"post"},
     fancybox: true, 
    motion: true
  };
</script>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container one-collumn sidebar-position-left page-home  ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"> <div class="site-meta  custom-logo ">

  <div class="custom-logo-site-title">
    <a href="http://www.shutdown.cn"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">天地维杰网</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">人如秋鸿来有信，事若春梦了无痕</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
    <ul id="menu" class="menu">
      
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />首页
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/redis/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-battery-full"></i> <br />Redis
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/java/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-coffee"></i> <br />java
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/linux/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-linux"></i> <br />linux
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/daily/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-bug"></i> <br />日常问题
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/spring/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-child"></i> <br />Spring和Springboot
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/spring/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-fire"></i> <br />Mac相关
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/jvm/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-gavel"></i> <br />中间件
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/front/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-bolt"></i> <br />前端
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/jvm/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-balance-scale"></i> <br />JVM
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/post/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />归档
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/about/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />关于
          </a>
        </li>
      
      <li class="menu-item menu-item-search">
        <a href="javascript:;" class="popup-trigger"> <i class="menu-item-icon fa fa-search fa-fw"></i> <br /> 搜索</a>
      </li>
    </ul>
    <div class="site-search">
      <div class="popup">
 <span class="search-icon fa fa-search"></span>
 <input type="text" id="local-search-input">
 <div id="local-search-result"></div>
 <span class="popup-btn-close">close</span>
</div>

    </div>
</nav>

 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
<section id="posts" class="posts-expand">
  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <header class="post-header">
      <h1 class="post-title" itemprop="name headline">
        <a class="post-title-link" href="http://www.shutdown.cn/post/%E6%9C%8D%E5%8A%A1%E5%AE%95%E6%9C%BA%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5/" itemprop="url">
        
        </a>
      </h1>
      <div class="post-meta">
      <span class="post-time">
<span class="post-meta-item-icon">
    <i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">时间：</span>
<time itemprop="dateCreated" datetime="2016-03-22T13:04:35+08:00" content="0001-01-01">
    0001-01-01
</time>
</span> 
      
       <span>
&nbsp; | &nbsp;
<span class="post-meta-item-icon">
    <i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读：</span>
<span class="leancloud-visitors-count">1403 字 ~7分钟</span>
</span>
      </div>
    </header>
    <div class="post-body" itemprop="articleBody">
    <p>Redis 3.2.3 crashed by signal: 11 服务宕机问题排查</p>
<h3 id="现象">现象</h3>
<p>Redis执行bgsave 、bgrewriteaof、全量scan等操作都会出现崩溃</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fallback" data-lang="fallback">=== REDIS BUG REPORT START: Cut &amp; paste starting from here ===

4664:C 13 Jul 13:44:19.092 # Redis 3.2.3 crashed by signal: 11
4664:C 13 Jul 13:44:19.092 # Crashed running the instuction at: 0x4234c0
4664:C 13 Jul 13:44:19.092 # Accessing address: (nil)
4664:C 13 Jul 13:44:19.092 # Failed assertion: &lt;no assertion failed&gt; (&lt;no file&gt;:0)
------ STACK TRACE ------
EIP:
redis-rdb-bgsave 0.0.0.0:7000 [cluster](dictNext+0x70)[0x4234c0]
Backtrace:
redis-rdb-bgsave 0.0.0.0:7000 [cluster](logStackTrace+0x29)[0x45d3d9]
redis-rdb-bgsave 0.0.0.0:7000 [cluster](sigsegvHandler+0xaa)[0x45d8ca]
/lib64/libpthread.so.0(+0xf630)[0x7f82f8e7d630]

</code></pre></div><div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fallback" data-lang="fallback">------ CURRENT CLIENT INFO ------
id=89347820 addr=127.0.0.1:63314 fd=104 name= age=35 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=bgsave
argv[0]: &#39;BGSAVE&#39;
32912:C 13 Jul 14:28:16.596 # ------------------------------------------------
32912:C 13 Jul 14:28:16.596 # !!! Software Failure. Press left mouse button to continue
32912:C 13 Jul 14:28:16.596 # Guru Meditation: &#34;Unknown encoding type&#34; #object.c:456
32912:C 13 Jul 14:28:16.596 # (forcing SIGSEGV in order to print the stack trace)
32912:C 13 Jul 14:28:16.596 # ------------------------------------------------
10430:M 13 Jul 14:28:16.672 # Background saving terminated by signal 11
 
=== REDIS BUG REPORT START: Cut &amp; paste starting from here ===
10430:M 13 Jul 15:01:55.933 # Redis 3.2.3 crashed by signal: 11
10430:M 13 Jul 15:01:55.933 # Crashed running the instuction at: 0x438ea0
10430:M 13 Jul 15:01:55.933 # Accessing address: (nil)
10430:M 13 Jul 15:01:55.933 # Failed assertion: &lt;no assertion failed&gt; (&lt;no file&gt;:0)
------ STACK TRACE ------
EIP:
/opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](scanCallback+0xb0)[0x438ea0]
 
Backtrace:
/opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](logStackTrace+0x29)[0x45d3d9]
/opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](sigsegvHandler+0xaa)[0x45d8ca]
/lib64/libpthread.so.0(+0xf630)[0x7f82f8e7d630]
/opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](scanCallback+0xb0)[0x438ea0]
/opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](dictScan+0x198)[0x423a28]
</code></pre></div><div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fallback" data-lang="fallback">=== REDIS BUG REPORT START: Cut &amp; paste starting from here ===
24773:S 15 Jul 17:29:29.787 # Redis 3.2.3 crashed by signal: 11
24773:S 15 Jul 17:29:29.787 # Crashed running the instuction at: 0x4231ea
24773:S 15 Jul 17:29:29.787 # Accessing address: (nil)
24773:S 15 Jul 17:29:29.787 # Failed assertion: &lt;no assertion failed&gt; (&lt;no file&gt;:0)
------ STACK TRACE ------
EIP:
/opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](dictFind+0x8a)[0x4231ea]
</code></pre></div><h3 id="排查">排查</h3>
<p>最开始生产的该实例已经是单点了，从节点虽然启动了，但是主节点无法生成dump文件进行主从同步，无法bgsave的操作，也无法进行数据传输的操作。正当我和同事讨论要不要开启aof备份时，这个主节点挂了，只能立即启动，但是数据丢了一半。这里有个教训，这种情况应该<strong>首先在实例开启AOF，这样在崩溃时才有还原的数据以及排查的数据。</strong></p>
<p>重新启动以后，我们立刻开启了aof备份，可以正常备份数据。当时如果开启了aof备份就好了，起码数据不会丢很多，开启aof备份以后，会立即进行全量的备份，将内存中的已有数据都写入aof备份文件。但是此时，造成崩溃的数据已经丢了，现在进行bgsave等操作等正常了。这时领导说要不升级下版本试试（这点要考），我们目前不能复现所以无法确定问题所在，所以没有同意进行升级。使用这个集群的项目组最近新上了功能，使用了bitmap的bitfield命令，但是没法定位问题，所以不能确定是否是这个原因（这点要考）。</p>
<p>因为想起mysql也有因为编码问题无法存储表情包只能使用utf8_mb4的情况，所以第二天特意找到很多表情码中文码进行读写测试，都没有出现崩溃的情况。可以正常进行数据读写。</p>
<p>第二天无事发生，到了第三天，又出现了类似的情况。首先是一个从节点挂掉，然后一个主节点成了单点，从节点重新启动不停向主节点请求数据同步，但主节点生成rdb始终是失败的。没过一会，主节点也失败了，这次有了aof的备份数据，直接启动节点就可以了，而且有了aof的节点数据。但是问题并没有解决。领导说要不升级到高版本试试，因为目前使用的版本是3.2.3，所以现在反正也无法定位到问题，不如死马当活马医，升级下版本试试。那就试试，于是在本地的虚拟机中搭建了3.2.12版本的实例，然后拿生产的aof备份文件进行导入启动，然后进行 scan 、bgsave等测试，确定是能够正常进行没有崩溃以后，便和业务约好一定时间进行维护，将该应用使用的集群的所有实例全部升级到了3.2.13版本。</p>
<p>生产稳定以后，就开始想办法复现问题定位原因了。改问题可以通过几种方式进行复现：</p>
<ol>
<li>使用该数据文件进行启动，然后执行 <code>save</code>、<code>bgsave</code>、<code>bgrewriteaof</code></li>
<li>使用改数据文件进行启动，然后进行<code>save</code>，使用less命令查看崩溃后生成的临时rdb文件temp-xxx.xxx.rdb的最后一个key，使用这个key在全局使用一个非常大的count进行scan，可以偶现崩溃情况。</li>
<li>使用该数据文件进行启动，然后执行全量scan可以偶现。</li>
</ol>
<p>为了找到问题的key，我尝试使用几种排查的方法，</p>
<ol>
<li>二分法：将aof备份文件给切分成等大小的10份、5份、2份，将每份数据的截断的命令进行删除后，非别启动实例导入每份数据，然后分别在每个实例上面执行bgsave命令，都能够正常的执行。没有出现崩溃的情况，因为对同一个key的操作是可能会分布到多个文件中，所以这个方法没法复现。</li>
<li>全局scan方式：启动实例并引入aof备份文件以后，使用java程序执行全局scan命令，<code>scan 0 match * count 600</code>直到全部数据执行完毕。看是否触发崩溃。经过多次试验，并不是每次都能够复现崩溃情况（有可能存在数据超时的情况），崩溃时记录下崩溃的时候执行的key，然后拿到这个key，将其所有的操作从aof文件中导出，在一个空实例中执行，再执行bgsave命令，没有复现崩溃的情况。每次崩溃时的key也不一样。</li>
<li>修改源码，在执行bgsave中崩溃的代码以及scanCallback崩溃时的代码中对key进行输出。但这种方式只能定位到出现崩溃时的前一个key，每次的也不一样。</li>
</ol>
<p>从以上的几次测试，可以看出，并不是特定的key数据导致的崩溃。</p>
<ol start="4">
<li>使用gdb打断点的方式，进行按步调试，但是崩溃发生的地方是循环中，因为key太多，也无法正常调试。</li>
</ol>
<p>使用个各种方式都没法定位到问题，后来想到，既然升级了版本以后，没有再出现崩溃的问题，那么应该是某个版本对bug进行了修复，然后就从3.2.3以后的版本往后逐个创建新虚拟机进行编译-&gt;启动-&gt;导入数据-&gt;bgsave，到3.2.6版本就没有出现这个问题了。然后就查看3.2.6这个版本的修改记录，https://github.com/redis/redis/blob/3.2.6/00-RELEASENOTES</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">
Upgrade urgency MODERATE: GEORADIUS, BITFIELD and Redis Cluster minor fixes.

This release mainly fixes three bugs:

1. A bug with BITFIELD that may cause the bitmap corruption when setting offsets
   larger than the current string size.

2. A GEORADIUS bug that may happen when using very large radius lengths, in
   the range of 10000km or alike, due to wrong bounding box calculation.

3. A bug with Redis Cluster which crashes when reading a nodes configuration
   file with zero bytes at the end, which sometimes happens with certain ext4
   configurations after a system crash.

</code></pre></div><p>前面不是提到了吗，使用这个集群的应用最近上了个新功能，使用了bitmap，3.2.6这个版本正好修复了bitfield命令的一个bug，使用aof文件解析工具waoffle，将aof文件解析为redis命令后，将所有的bitfield命令导出。最开始没有对bug修复描述的<code>A bug with BITFIELD that may cause the bitmap corruption when setting offsets larger than the current string size</code>正确理解，只能通过根据bug修复的代码进行反推。</p>
<!-- raw HTML omitted -->
<p>在源码处增加对执行命令、key及参数进行输出，将符合修复代码部分的命令进行输出，源码修改如下：</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#000">bitops</span><span style="color:#000;font-weight:bold">.</span><span style="color:#000">c</span>

		<span style="color:#0000cf;font-weight:bold">958</span>         <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">opcode</span> <span style="color:#ce5c00;font-weight:bold">!</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">BITFIELDOP_GET</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#0000cf;font-weight:bold">959</span>             <span style="color:#000">readonly</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">0</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#0000cf;font-weight:bold">960</span>             <span style="color:#000">if</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">higest_write_offset</span><span style="color:#ce5c00;font-weight:bold">!</span><span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#0000cf;font-weight:bold">0</span> <span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#ce5c00;font-weight:bold">&amp;</span> <span style="color:#000">higest_write_offset</span> <span style="color:#ce5c00;font-weight:bold">&lt;</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">bitoffset</span> <span style="color:#ce5c00;font-weight:bold">+</span> <span style="color:#000">bits</span> <span style="color:#ce5c00;font-weight:bold">-</span> <span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">{</span>
    <span style="color:#0000cf;font-weight:bold">961</span>                 <span style="color:#000">serverLog</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">LL_WARNING</span><span style="color:#000;font-weight:bold">,</span><span style="color:#4e9a06"></span><span style="color:#4e9a06">&#34;</span><span style="color:#4e9a06">key=&gt;%s,higest:%d,sum:%d,bitoffset:%d,bits:%d</span><span style="color:#4e9a06">&#34;</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">argv</span><span style="color:#000;font-weight:bold">[</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">]</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">ptr</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">higest_write_offset</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000;font-weight:bold">(</span>        <span style="color:#000">bitoffset</span> <span style="color:#ce5c00;font-weight:bold">+</span> <span style="color:#000">bits</span> <span style="color:#ce5c00;font-weight:bold">-</span> <span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">bitoffset</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">bits</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#0000cf;font-weight:bold">962</span>             <span style="color:#000;font-weight:bold">}</span>
    <span style="color:#0000cf;font-weight:bold">963</span>             <span style="color:#000">higest_write_offset</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">bitoffset</span> <span style="color:#ce5c00;font-weight:bold">+</span> <span style="color:#000">bits</span> <span style="color:#ce5c00;font-weight:bold">-</span> <span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#0000cf;font-weight:bold">964</span>             <span style="color:#8f5902;font-style:italic">//if (higest_write_offset &lt; bitoffset + bits - 1)
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#0000cf;font-weight:bold">965</span>             <span style="color:#8f5902;font-style:italic">//    higest_write_offset = bitoffset + bits - 1;
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#0000cf;font-weight:bold">966</span>             <span style="color:#8f5902;font-style:italic">/* INCRBY and SET require another argument. */</span>
    <span style="color:#0000cf;font-weight:bold">967</span>             <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">getLongLongFromObjectOrReply</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">argv</span><span style="color:#000;font-weight:bold">[</span><span style="color:#000">j</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#0000cf;font-weight:bold">3</span><span style="color:#000;font-weight:bold">]</span><span style="color:#000;font-weight:bold">,</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">i64</span><span style="color:#000;font-weight:bold">,</span><span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#ce5c00;font-weight:bold">!</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">C_OK</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">{</span>
    <span style="color:#0000cf;font-weight:bold">968</span>                 <span style="color:#000">zfree</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">ops</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#0000cf;font-weight:bold">969</span>                 <span style="color:#204a87;font-weight:bold">return</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#0000cf;font-weight:bold">970</span>             <span style="color:#000;font-weight:bold">}</span>
    <span style="color:#0000cf;font-weight:bold">971</span>         <span style="color:#000;font-weight:bold">}</span>
</code></pre></div><p>符合修复部分的命令都是那种在一次bitfield命令中执行多次set命令的情况，而且只有后面命令的offset的值小于前面命令的offset值的命令才符合修复代码中的判断。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">BITFIELD r_s_b-f416-45dd-9016-3c19c7e934f5 <span style="color:#204a87">set</span> u1 <span style="color:#0000cf;font-weight:bold">12</span> <span style="color:#0000cf;font-weight:bold">1</span> <span style="color:#204a87">set</span> u1 <span style="color:#0000cf;font-weight:bold">3</span> <span style="color:#0000cf;font-weight:bold">1</span>
BITFIELD r_s_5-62DE-40C4-8FAE-602146E6A224 <span style="color:#204a87">set</span> u1 <span style="color:#0000cf;font-weight:bold">129</span> <span style="color:#0000cf;font-weight:bold">1</span> <span style="color:#204a87">set</span> u1 <span style="color:#0000cf;font-weight:bold">13</span> <span style="color:#0000cf;font-weight:bold">1</span>
</code></pre></div><p>中间还做过一些通过分批执行aof备份提取的bitfield命令的定位key的测试，但是这个不是特定的key导致的，所以其实是无用排查。</p>
<p>最后开始分析源码，来进行故障原因分析，具体的涉及的代码可以看中文注释的所在位置：</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#8f5902;font-style:italic">//bitops.c
</span><span style="color:#8f5902;font-style:italic"></span><span style="color:#204a87;font-weight:bold">void</span> <span style="color:#000">bitfieldCommand</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">client</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">c</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#000">robj</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">o</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000">size_t</span> <span style="color:#000">bitoffset</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">int</span> <span style="color:#000">j</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">numops</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">0</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">changes</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">0</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">struct</span> <span style="color:#000">bitfieldOp</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">ops</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">;</span> <span style="color:#8f5902;font-style:italic">/* Array of ops to execute at end. */</span>
    <span style="color:#204a87;font-weight:bold">int</span> <span style="color:#000">owtype</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">BFOVERFLOW_WRAP</span><span style="color:#000;font-weight:bold">;</span> <span style="color:#8f5902;font-style:italic">/* Overflow type. */</span>
    <span style="color:#204a87;font-weight:bold">int</span> <span style="color:#000">readonly</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#8f5902;font-style:italic">//最大写入偏移量
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#204a87;font-weight:bold">long</span> <span style="color:#000">higest_write_offset</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">0</span><span style="color:#000;font-weight:bold">;</span>
   
  	<span style="color:#a40000">…</span><span style="color:#a40000">…</span><span style="color:#a40000">省</span><span style="color:#a40000">略</span><span style="color:#a40000">部</span><span style="color:#a40000">分</span><span style="color:#a40000">代</span><span style="color:#a40000">码</span><span style="color:#a40000">…</span><span style="color:#a40000">…</span>
  	
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">opcode</span> <span style="color:#ce5c00;font-weight:bold">!</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">BITFIELDOP_GET</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
      <span style="color:#000">readonly</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">0</span><span style="color:#000;font-weight:bold">;</span>
      <span style="color:#8f5902;font-style:italic">//这里可以看到，这个higest_write_offset是每个循环都设置的
</span><span style="color:#8f5902;font-style:italic"></span>      <span style="color:#8f5902;font-style:italic">//一般情况下没问题，但是如果一次bitfield命令执行多次的话
</span><span style="color:#8f5902;font-style:italic"></span>      <span style="color:#8f5902;font-style:italic">//如 `BITFIELD read_status_d74cb723-1db5-489e-9adb-80d53e305d17 set u1 364 1 set u1 124 1`
</span><span style="color:#8f5902;font-style:italic"></span>      <span style="color:#8f5902;font-style:italic">//如果是这个命令执行的话，higest_write_offset会被设置为一个较小的值，如上面的命令会设为124
</span><span style="color:#8f5902;font-style:italic"></span>      <span style="color:#8f5902;font-style:italic">//再看3.2.6对bitfield bug修复所改的代码，就是增加了一个判断，是higest_write_offset的值会是命令中的最大的值
</span><span style="color:#8f5902;font-style:italic"></span>      <span style="color:#8f5902;font-style:italic">//if (higest_write_offset &lt; bitoffset + bits - 1)
</span><span style="color:#8f5902;font-style:italic"></span>      <span style="color:#8f5902;font-style:italic">//          higest_write_offset = bitoffset + bits - 1;
</span><span style="color:#8f5902;font-style:italic"></span>      <span style="color:#8f5902;font-style:italic">//
</span><span style="color:#8f5902;font-style:italic"></span>      <span style="color:#000">higest_write_offset</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">bitoffset</span> <span style="color:#ce5c00;font-weight:bold">+</span> <span style="color:#000">bits</span> <span style="color:#ce5c00;font-weight:bold">-</span> <span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">;</span>
      <span style="color:#8f5902;font-style:italic">/* INCRBY and SET require another argument. */</span>
      <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">getLongLongFromObjectOrReply</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">argv</span><span style="color:#000;font-weight:bold">[</span><span style="color:#000">j</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#0000cf;font-weight:bold">3</span><span style="color:#000;font-weight:bold">]</span><span style="color:#000;font-weight:bold">,</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">i64</span><span style="color:#000;font-weight:bold">,</span><span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#ce5c00;font-weight:bold">!</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">C_OK</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">{</span>
        <span style="color:#000">zfree</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">ops</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">return</span><span style="color:#000;font-weight:bold">;</span>
      <span style="color:#000;font-weight:bold">}</span>
    <span style="color:#000;font-weight:bold">}</span>

   	<span style="color:#a40000">…</span><span style="color:#a40000">…</span><span style="color:#a40000">省</span><span style="color:#a40000">略</span><span style="color:#a40000">部</span><span style="color:#a40000">分</span><span style="color:#a40000">代</span><span style="color:#a40000">码</span><span style="color:#a40000">…</span><span style="color:#a40000">…</span>
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">readonly</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#8f5902;font-style:italic">/* Lookup for read is ok if key doesn&#39;t exit, but errors
</span><span style="color:#8f5902;font-style:italic">         * if it&#39;s not a string. */</span>
        <span style="color:#000">o</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">lookupKeyRead</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">db</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">argv</span><span style="color:#000;font-weight:bold">[</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">]</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">o</span> <span style="color:#ce5c00;font-weight:bold">!</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87">NULL</span> <span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#ce5c00;font-weight:bold">&amp;</span> <span style="color:#000">checkType</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">o</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">OBJ_STRING</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#204a87;font-weight:bold">return</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span> <span style="color:#204a87;font-weight:bold">else</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#8f5902;font-style:italic">/* Lookup by making room up to the farest bit reached by
</span><span style="color:#8f5902;font-style:italic">         * this operation. */</span>
        <span style="color:#8f5902;font-style:italic">//非只读操作
</span><span style="color:#8f5902;font-style:italic"></span>        <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">o</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">lookupStringForBitCommand</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">higest_write_offset</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#204a87;font-weight:bold">return</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>
  	<span style="color:#a40000">…</span><span style="color:#a40000">…</span><span style="color:#a40000">省</span><span style="color:#a40000">略</span><span style="color:#a40000">部</span><span style="color:#a40000">分</span><span style="color:#a40000">代</span><span style="color:#a40000">码</span><span style="color:#a40000">…</span><span style="color:#a40000">…</span>
<span style="color:#000;font-weight:bold">}</span>

<span style="color:#8f5902;font-style:italic">/* This is an helper function for commands implementations that need to write
</span><span style="color:#8f5902;font-style:italic"> * bits to a string object. The command creates or pad with zeroes the string
</span><span style="color:#8f5902;font-style:italic"> * so that the &#39;maxbit&#39; bit can be addressed. The object is finally
</span><span style="color:#8f5902;font-style:italic"> * returned. Otherwise if the key holds a wrong type NULL is returned and
</span><span style="color:#8f5902;font-style:italic"> * an error is sent to the client. */</span>
<span style="color:#8f5902;font-style:italic">// The command creates or pad with zeroes the string so that the &#39;maxbit&#39; bit can be addressed.
</span><span style="color:#8f5902;font-style:italic"></span><span style="color:#8f5902;font-style:italic">// 这个命令创建string或将string填充0，这样 maxbit 的位才能被定位
</span><span style="color:#8f5902;font-style:italic"></span><span style="color:#8f5902;font-style:italic">// 这个maxbit的值就是higest_write_offset
</span><span style="color:#8f5902;font-style:italic"></span><span style="color:#000">robj</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">lookupStringForBitCommand</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">client</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">c</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">size_t</span> <span style="color:#000">maxbit</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
	  <span style="color:#8f5902;font-style:italic">//将位数转为字节数 
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#000">size_t</span> <span style="color:#000">byte</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">maxbit</span> <span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#ce5c00;font-weight:bold">&gt;</span> <span style="color:#0000cf;font-weight:bold">3</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000">robj</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">o</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">lookupKeyWrite</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">db</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">argv</span><span style="color:#000;font-weight:bold">[</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">]</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">o</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#000">o</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">createObject</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">OBJ_STRING</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">sdsnewlen</span><span style="color:#000;font-weight:bold">(</span><span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">byte</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">dbAdd</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">db</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">argv</span><span style="color:#000;font-weight:bold">[</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">]</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">o</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span> <span style="color:#204a87;font-weight:bold">else</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">checkType</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">o</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">OBJ_STRING</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">o</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">dbUnshareStringValue</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">db</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">c</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">argv</span><span style="color:#000;font-weight:bold">[</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">]</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">o</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">o</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">ptr</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">sdsgrowzero</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">o</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">ptr</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">byte</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>
    <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">o</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000;font-weight:bold">}</span>

<span style="color:#8f5902;font-style:italic">/* Grow the sds to have the specified length. Bytes that were not part of
</span><span style="color:#8f5902;font-style:italic"> * the original length of the sds will be set to zero.
</span><span style="color:#8f5902;font-style:italic"> *
</span><span style="color:#8f5902;font-style:italic"> * if the specified length is smaller than the current length, no operation
</span><span style="color:#8f5902;font-style:italic"> * is performed. */</span>
<span style="color:#000">sds</span> <span style="color:#000">sdsgrowzero</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">sds</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">size_t</span> <span style="color:#000">len</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
  	<span style="color:#8f5902;font-style:italic">//获取当前字符串的长度
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#000">size_t</span> <span style="color:#000">curlen</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">sdslen</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
		<span style="color:#8f5902;font-style:italic">//如果最大长度小于当前长度则不做任何操作
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">len</span> <span style="color:#ce5c00;font-weight:bold">&lt;</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">curlen</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">;</span>
	  <span style="color:#8f5902;font-style:italic">//否则
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#000">s</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">sdsMakeRoomFor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">len</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#000">curlen</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">;</span>

    <span style="color:#8f5902;font-style:italic">/* Make sure added region doesn&#39;t contain garbage */</span>
    <span style="color:#000">memset</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#000">curlen</span><span style="color:#000;font-weight:bold">,</span><span style="color:#0000cf;font-weight:bold">0</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">len</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#000">curlen</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span> <span style="color:#8f5902;font-style:italic">/* also set trailing \0 byte */</span>
  	<span style="color:#8f5902;font-style:italic">//这里会将 sds的长度设置为给定的长度，这个len是上面的(higest_write_offset &gt;&gt; 3) +1的长度
</span><span style="color:#8f5902;font-style:italic"></span>    <span style="color:#000">sdssetlen</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">len</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000;font-weight:bold">}</span>


<span style="color:#8f5902;font-style:italic">/* Enlarge the free space at the end of the sds string so that the caller
</span><span style="color:#8f5902;font-style:italic"> * is sure that after calling this function can overwrite up to addlen
</span><span style="color:#8f5902;font-style:italic"> * bytes after the end of the string, plus one more byte for nul term.
</span><span style="color:#8f5902;font-style:italic"> *
</span><span style="color:#8f5902;font-style:italic"> * Note: this does not change the *length* of the sds string as returned
</span><span style="color:#8f5902;font-style:italic"> * by sdslen(), but only the free buffer space we have. */</span>
<span style="color:#8f5902;font-style:italic">//在sds字符串后扩大空闲空间以便调用这个方法后可以在字符串后覆写新增的长度的字节，额外增加一个字节标识空位
</span><span style="color:#8f5902;font-style:italic"></span><span style="color:#8f5902;font-style:italic">//这个操作不会修改sds字符串的长度，只会改变空闲缓冲空间
</span><span style="color:#8f5902;font-style:italic"></span><span style="color:#000">sds</span> <span style="color:#000">sdsMakeRoomFor</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">sds</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">size_t</span> <span style="color:#000">addlen</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#204a87;font-weight:bold">void</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">sh</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">newsh</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000">size_t</span> <span style="color:#000">avail</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">sdsavail</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000">size_t</span> <span style="color:#000">len</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">newlen</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">char</span> <span style="color:#000">type</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">oldtype</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">[</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">]</span> <span style="color:#ce5c00;font-weight:bold">&amp;</span> <span style="color:#000">SDS_TYPE_MASK</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">int</span> <span style="color:#000">hdrlen</span><span style="color:#000;font-weight:bold">;</span>

    <span style="color:#8f5902;font-style:italic">/* Return ASAP if there is enough space left. */</span>
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">avail</span> <span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">addlen</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">;</span>

    <span style="color:#000">len</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">sdslen</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000">sh</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">char</span><span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000">s</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#000">sdsHdrSize</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">oldtype</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000">newlen</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">len</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#000">addlen</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">newlen</span> <span style="color:#ce5c00;font-weight:bold">&lt;</span> <span style="color:#000">SDS_MAX_PREALLOC</span><span style="color:#000;font-weight:bold">)</span>
        <span style="color:#000">newlen</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#0000cf;font-weight:bold">2</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">else</span>
        <span style="color:#000">newlen</span> <span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">SDS_MAX_PREALLOC</span><span style="color:#000;font-weight:bold">;</span>

    <span style="color:#000">type</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">sdsReqType</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">newlen</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>

    <span style="color:#8f5902;font-style:italic">/* Don&#39;t use type 5: the user is appending to the string and type 5 is
</span><span style="color:#8f5902;font-style:italic">     * not able to remember empty space, so sdsMakeRoomFor() must be called
</span><span style="color:#8f5902;font-style:italic">     * at every appending operation. */</span>
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">type</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">SDS_TYPE_5</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000">type</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">SDS_TYPE_8</span><span style="color:#000;font-weight:bold">;</span>

    <span style="color:#000">hdrlen</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">sdsHdrSize</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">type</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">oldtype</span><span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#000">type</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#000">newsh</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">s_realloc</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">sh</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">hdrlen</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#000">newlen</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">newsh</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">s</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">char</span><span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000">newsh</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#000">hdrlen</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span> <span style="color:#204a87;font-weight:bold">else</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#8f5902;font-style:italic">/* Since the header size changes, need to move the string forward,
</span><span style="color:#8f5902;font-style:italic">         * and can&#39;t use realloc */</span>
        <span style="color:#000">newsh</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">s_malloc</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">hdrlen</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#000">newlen</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">if</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">newsh</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">memcpy</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">char</span><span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000">newsh</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#000">hdrlen</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">len</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">s_free</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">sh</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">s</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">char</span><span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000">newsh</span><span style="color:#ce5c00;font-weight:bold">+</span><span style="color:#000">hdrlen</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#000">s</span><span style="color:#000;font-weight:bold">[</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">]</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">type</span><span style="color:#000;font-weight:bold">;</span>
      	<span style="color:#8f5902;font-style:italic">//这里的sdssetlen实际上是设置了sds的长度 ，及strlen返回的结果
</span><span style="color:#8f5902;font-style:italic"></span>        <span style="color:#000">sdssetlen</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">len</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>
    <span style="color:#000">sdssetalloc</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">newlen</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">return</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000;font-weight:bold">}</span>

<span style="color:#204a87;font-weight:bold">static</span> <span style="color:#204a87;font-weight:bold">inline</span> <span style="color:#204a87;font-weight:bold">void</span> <span style="color:#000">sdssetlen</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">sds</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#000">size_t</span> <span style="color:#000">newlen</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#204a87;font-weight:bold">unsigned</span> <span style="color:#204a87;font-weight:bold">char</span> <span style="color:#000">flags</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">s</span><span style="color:#000;font-weight:bold">[</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">]</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#204a87;font-weight:bold">switch</span><span style="color:#000;font-weight:bold">(</span><span style="color:#000">flags</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">SDS_TYPE_MASK</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
        <span style="color:#204a87;font-weight:bold">case</span> <span style="color:#f57900">SDS_TYPE_5</span><span style="color:#000;font-weight:bold">:</span>
            <span style="color:#000;font-weight:bold">{</span>
                <span style="color:#204a87;font-weight:bold">unsigned</span> <span style="color:#204a87;font-weight:bold">char</span> <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">fp</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">unsigned</span> <span style="color:#204a87;font-weight:bold">char</span><span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">)</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#0000cf;font-weight:bold">1</span><span style="color:#000;font-weight:bold">;</span>
                <span style="color:#ce5c00;font-weight:bold">*</span><span style="color:#000">fp</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">SDS_TYPE_5</span> <span style="color:#ce5c00;font-weight:bold">|</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">newlen</span> <span style="color:#ce5c00;font-weight:bold">&lt;</span><span style="color:#ce5c00;font-weight:bold">&lt;</span> <span style="color:#000">SDS_TYPE_BITS</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#000;font-weight:bold">}</span>
            <span style="color:#204a87;font-weight:bold">break</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">case</span> <span style="color:#f57900">SDS_TYPE_8</span><span style="color:#000;font-weight:bold">:</span>
            <span style="color:#000">SDS_HDR</span><span style="color:#000;font-weight:bold">(</span><span style="color:#0000cf;font-weight:bold">8</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">)</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">len</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">newlen</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87;font-weight:bold">break</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">case</span> <span style="color:#f57900">SDS_TYPE_16</span><span style="color:#000;font-weight:bold">:</span>
            <span style="color:#000">SDS_HDR</span><span style="color:#000;font-weight:bold">(</span><span style="color:#0000cf;font-weight:bold">16</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">)</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">len</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">newlen</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87;font-weight:bold">break</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">case</span> <span style="color:#f57900">SDS_TYPE_32</span><span style="color:#000;font-weight:bold">:</span>
            <span style="color:#000">SDS_HDR</span><span style="color:#000;font-weight:bold">(</span><span style="color:#0000cf;font-weight:bold">32</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">)</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">len</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">newlen</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87;font-weight:bold">break</span><span style="color:#000;font-weight:bold">;</span>
        <span style="color:#204a87;font-weight:bold">case</span> <span style="color:#f57900">SDS_TYPE_64</span><span style="color:#000;font-weight:bold">:</span>
            <span style="color:#000">SDS_HDR</span><span style="color:#000;font-weight:bold">(</span><span style="color:#0000cf;font-weight:bold">64</span><span style="color:#000;font-weight:bold">,</span><span style="color:#000">s</span><span style="color:#000;font-weight:bold">)</span><span style="color:#ce5c00;font-weight:bold">-</span><span style="color:#ce5c00;font-weight:bold">&gt;</span><span style="color:#000">len</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">newlen</span><span style="color:#000;font-weight:bold">;</span>
            <span style="color:#204a87;font-weight:bold">break</span><span style="color:#000;font-weight:bold">;</span>
    <span style="color:#000;font-weight:bold">}</span>
<span style="color:#000;font-weight:bold">}</span>
</code></pre></div><div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">BITFIELD r_s_8888_8888_8888_8888 <span style="color:#204a87">set</span> u1 <span style="color:#0000cf;font-weight:bold">202</span> <span style="color:#0000cf;font-weight:bold">1</span> <span style="color:#204a87">set</span> u1 <span style="color:#0000cf;font-weight:bold">19</span> <span style="color:#0000cf;font-weight:bold">1</span>
</code></pre></div><p>从以上代码可以，如果在一次<code>bitfield</code>命令中执行多次set命令，并且后面命令的offset的值比前面的值小的话，会影响到sds字符传的长度的值。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">-----------------------------
| | | | | | | | | | | | | | |
-----------------------------

第一次执行设置大offset命令

-----------------------------
|0|0|0|0|0|0|0|0|0|0|0|0|0|1|
-----------------------------
                           ^ higest_write_offset

第二次执行设置大offset命令

-----------------------------
|0|0|0|0|0|1|0|0|0|0|0|0|0|1|
-----------------------------
					 ^ higest_write_offset
|---sds----|
最终的sds的长度被设置为后面的短的位置，字符串的长度被截断了，这时就算执行bitfield命令获取高位的位值获取到的也只是0。


</code></pre></div><p>sds的组成部分为，len、 alloc、 flags 、buf[]</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fallback" data-lang="fallback">//以 sdshdr64举例
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
</code></pre></div><p>这个buf[]为一个柔性数组，即未给定长度可以动态调整长度的数组。sds的扩容策略是若sds中剩余空闲长度大于新增内容的长度，则直接在柔性数组的buf末尾追加，无需扩容。若sds中剩余空闲长度小于或等于新增内容的长度，则分两种情况：(当前长度+新增长度)&lt;1MB，按(当前长度+新增长度)的2被扩容；若(当前长度+新增长度)&gt;1MB，则按(当前长度+新增长度)+1MB进行扩容。然后根据新长度重新选取存储类型，并分配空间。若无需更改类型，则通过realloc扩大柔性数据即可，否则则需要重新开辟内存，将原字符串的buf内容移动到新位置。</p>
<p>根据故障的数据，最大的为900多，所以应该有会触发柔性数组由sdshdr8(256以内)向sdshdr16(65536)的扩容。并且前面的<code>higest_write_offset</code>的循环设置，会导致sds截断，如下面的命令测试。sds <code>strlen r_s_8888_8888_8888_8888</code> 的长度的值为 19&raquo;3 +1 == 19/8 + 1 = 3</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">
127.0.0.1:8888&gt; BITFIELD r_s_8888_8888_8888_8888 <span style="color:#204a87">set</span> u1 <span style="color:#0000cf;font-weight:bold">202</span> <span style="color:#0000cf;font-weight:bold">1</span> <span style="color:#204a87">set</span> u1 <span style="color:#0000cf;font-weight:bold">19</span> <span style="color:#0000cf;font-weight:bold">1</span>
1<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#ce5c00;font-weight:bold">(</span>integer<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#0000cf;font-weight:bold">1</span>
2<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#ce5c00;font-weight:bold">(</span>integer<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#0000cf;font-weight:bold">0</span>
127.0.0.1:8888&gt; bitfield r_s_8888_8888_8888_8888 get u1 <span style="color:#0000cf;font-weight:bold">202</span>
1<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#ce5c00;font-weight:bold">(</span>integer<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#0000cf;font-weight:bold">0</span>
127.0.0.1:8888&gt; bitfield r_s_8888_8888_8888_8888 get u1 <span style="color:#0000cf;font-weight:bold">19</span>
1<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#ce5c00;font-weight:bold">(</span>integer<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#0000cf;font-weight:bold">1</span>
127.0.0.1:8888&gt; strlen r_s_8888_8888_8888_8888
<span style="color:#ce5c00;font-weight:bold">(</span>integer<span style="color:#ce5c00;font-weight:bold">)</span> <span style="color:#0000cf;font-weight:bold">3</span>
</code></pre></div><p>由此我推测，被截断的剩下的那部分内存是导致redis崩溃的原因，比如说这块内存被回收或间接的使用影响到了其他的dictEntry内存的key的部分，或者影响到了其他的redisobject的encoding部分，导致数据不完整，以至于扫描到对应的key，或者获取对应的dictEntry的key或者encoding等等，就会因为数据的错乱而导致崩溃。这个情况必须是bug代码配合大量数据执行才能出现的情况。以目前的能力只能推测到这里，没法进行再深入的验证了。</p>
<p>另外当时有一个排查方向是怀疑在执行bug代码时正好进行频繁rehash导致有问题，但是看了rehash的代码，rehash的过程只是hashtable[0] 和 hashtable[1]的交替扩容及key的hash值的重新计算和dictEntry与hashtable的bucket索引的重新绑定，并没有涉及到dictEntry以及redisObject的内存变动，所以排除rehash造成的该崩溃。</p>
<p>这个问题排查的难点是虽然可以稳定的复现，但是复现时的数据不是固定的数据，复现方式多样（save ,bgsave, bgrewriteaof, scan 等等），第一次故障出现时，因为没有数据所以没法复现，而且bgsave都是失败的，主从也无法进行同步，数据迁移等等，所以排查起来非常麻烦。最后还是通过版本比对进行反推问题产生原因。C语言太妙了。</p>

    </div>
    <footer class="post-footer">
     

     <div class="post-nav">
    <div class="post-nav-next post-nav-item">
    
        <a href="http://www.shutdown.cn/post/%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6/" rel="next" title="">
        <i class="fa fa-chevron-left"></i> 
        </a>
    
    </div>

    <div class="post-nav-prev post-nav-item">
    
        <a href="http://www.shutdown.cn/post/%E6%B7%B1%E5%85%A5%E5%89%96%E6%9E%90redis%E5%AE%A2%E6%88%B7%E7%AB%AFjedis%E7%9A%84%E7%89%B9%E6%80%A7%E5%92%8C%E5%8E%9F%E7%90%86/" rel="prev" title="">
         <i class="fa fa-chevron-right"></i>
        </a>
    
    </div>
</div>
      
     
     
     






    </footer>
  </article>
</section>

          </div>
        </div>
        <div class="sidebar-toggle">
  <div class="sidebar-toggle-line-wrap">
    <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
    <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
    <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
  </div>
</div>
<aside id="sidebar" class="sidebar">
  <div class="sidebar-inner">

    <section class="site-overview sidebar-panel  sidebar-panel-active ">
      <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image"
        src="http://www.shutdown.cn/img/author.jpg"
        alt="不与天斗Domino" />
    <p class="site-author-name" itemprop="name">不与天斗Domino</p>
    <p class="site-description motion-element" itemprop="description"> 
        Programmer &amp; Architect</p>
</div>
      <nav class="site-state motion-element">
    <div class="site-state-item site-state-posts">
      <a href="http://www.shutdown.cn/post/">
        <span class="site-state-item-count">176</span>
        <span class="site-state-item-name">日志</span>
      </a>
    </div>
    <div class="site-state-item site-state-categories">    
        <a href="http://www.shutdown.cn/categories/">      
         
        <span class="site-state-item-count">4</span>
        
        <span class="site-state-item-name">分类</span>
        
        </a>
    </div>

    <div class="site-state-item site-state-tags">
        <a href="http://www.shutdown.cn/tags/">
         
        <span class="site-state-item-count">6</span>
        
        <span class="site-state-item-name">标签</span>
        </a>
    </div>
</nav>
      
      

      

      <div class="links-of-blogroll motion-element inline">
<script type="text/javascript" src="//rf.revolvermaps.com/0/0/8.js?i=&amp;m=0&amp;s=220&amp;c=ff0000&amp;cr1=ffffff&amp;f=arial&amp;l=33&amp;bv=35" async="async"></script>
</div>

    </section>
    
  </div>
</aside>

      </div>
    </main>
   
    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  <span itemprop="copyrightYear">  &copy; 
  2009 - 2022</span>
  <span class="with-love"><i class="fa fa-heart"></i></span>
  <span class="author" itemprop="copyrightHolder">天地维杰网</span>
  <span class="icp" itemprop="copyrightHolder"><a href="https://beian.miit.gov.cn/" target="_blank">京ICP备13019191号-1</a></span>
</div>
<div class="powered-by">
  Powered by - <a class="theme-link" href="http://gohugo.io" target="_blank" title="hugo" >Hugo v0.63.2</a>
</div>
<div class="theme-info">
  Theme by - <a class="theme-link" href="https://github.com/xtfly/hugo-theme-next" target="_blank"> NexT
  </a>
</div>


      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
      <span id="scrollpercent"><span>0</span>%</span>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/jquery/index.js?v=2.1.3"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/fastclick/lib/fastclick.min.js?v=1.0.6"></script> 
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/velocity/velocity.min.js?v=1.2.1"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/velocity/velocity.ui.min.js?v=1.2.1"></script>
<script src="http://www.shutdown.cn/js/vendor/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>

<script src="http://www.shutdown.cn/js/vendor/fancybox/jquery.fancybox.pack.js?v=2.1.5"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/utils.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/motion.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/affix.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/schemes/pisces.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/scrollspy.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/post-details.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/toc.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/bootstrap.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js"],
    jax: ["input/TeX", "output/HTML-CSS"],
    tex2jax: {
      inlineMath: [ ['$','$'] ],
      displayMath: [ ['$$','$$'] ],
      processEscapes: true
    },
    "HTML-CSS": { fonts: ["TeX"] }
  });
</script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML' async></script>
</body>
</html>